package ar.edu.uba.fi.jmit.aspecter.parser;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import ar.edu.uba.fi.jmit.aspecter.parser.exception.XMLParserRuntimeException;

public class XMLMonitorEngineParser extends DefaultHandler {
	
	private static final String MONITORENGINE_TAG = "monitorengine";
	private static final String ENVIROMENT_MONITORENGINE_TAG = "enviroment";
	private static final String CONNECTION_TAG = "connection";
	private static final String PROTOCOL_CONNECTION_TAG = "protocol";
	private static final String IP_CONNECTION_TAG = "ip";
	private static final String PORT_CONNECTION_TAG = "port";
	private static final String CONTEXT_CONNECTION_TAG = "context";
	
	private String enviroment;
	private Map<String,String> props = new HashMap<String, String>();
	private boolean parseConnection;
	private int enviromentCounter;
	
	/**
	 * Punto de entrada para el parseo
	 * 
	 * @param pathToFile path del archivo a parsear.
	 * @throws SAXException
	 * @throws IOException
	 */
	public static Map<String,String> parse(String pathToFile, String enviroment) throws SAXException, IOException {
		XMLReader xr = XMLReaderFactory.createXMLReader();
		XMLMonitorEngineParser handler = new XMLMonitorEngineParser(enviroment);
		xr.setContentHandler(handler);
		xr.setErrorHandler(handler);
		FileReader r = new FileReader(pathToFile);
		xr.parse(new InputSource(r));
		return handler.getMonitorEngineProps();
	}
	
	public XMLMonitorEngineParser(String enviroment){
		this.enviroment = enviroment;
		this.parseConnection = false;
		this.enviromentCounter = 0;
	}

	private Map<String, String> getMonitorEngineProps() {
		return this.props;
	}
	
	private void validateMonitorEngineParse(Attributes atts){
		if (atts.getIndex(ENVIROMENT_MONITORENGINE_TAG) == -1){
			if (this.enviromentCounter == 0){
				this.enviromentCounter++;
			}else{
				throw new XMLParserRuntimeException("Enviroment tag of the MonitorEngine is missing");
			}
		}else{
			this.enviromentCounter++;
		}
	}
	
	private void parseMonitorEngine(Attributes atts){
		if (atts.getIndex(ENVIROMENT_MONITORENGINE_TAG) != -1){
			String env = atts.getValue(ENVIROMENT_MONITORENGINE_TAG);
			if (this.enviroment.equals(env)){
				this.parseConnection = true;
			}
		}else{
			if (this.enviromentCounter == 1){
				this.parseConnection = true;
			}
		}
	}
	
	private void validateConnectionParse(Attributes atts){
		if (atts.getIndex(PROTOCOL_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Name tag of the method is missing");
		}
		if (atts.getIndex(IP_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Return tag of the method is missing");
		}
		if (atts.getIndex(PORT_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Class tag of the method is missing");
		}
		if (atts.getIndex(CONTEXT_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Class tag of the method is missing");
		}
	}
	
	private void parseConnection(Attributes atts){
		String protocol = atts.getValue(PROTOCOL_CONNECTION_TAG);
		String ip = atts.getValue(IP_CONNECTION_TAG);
		String port = atts.getValue(PORT_CONNECTION_TAG);
		String context = atts.getValue(CONTEXT_CONNECTION_TAG);
		
		this.props.put("protocol", protocol);
		this.props.put("ip", ip);
		this.props.put("port", port);
		this.props.put("context", "/" + context);
		this.parseConnection = false;
	}
	
	@Override
	public void startElement(String uri, String name, String qName,	Attributes atts) throws SAXException {
		if (qName == MONITORENGINE_TAG){
			this.validateMonitorEngineParse(atts);
			this.parseMonitorEngine(atts);
		}
		if (this.parseConnection && qName == CONNECTION_TAG){
			this.validateConnectionParse(atts);
			this.parseConnection(atts);
		}
	}

}
